﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Seagull.Configuration;
using Seagull.DAL;
using Seagull.DAL.Helpers;
using Seagull.Generic;

namespace Seagull.Backup
{
    /// <summary>
    /// 压缩工作流程：
    ///     1. 查找本地超过保存期限的所有日期目录
    ///     2. 若压缩目录下已有同名目录则删除（可能是未完成的压缩）
    ///     3. 依次压缩每一天的解析后数据，每压缩完一天的数据，将该日的解析后数据删除
    /// </summary>
    public class CompressJob : MaintenanceJob
    {
        readonly PathHelper _sourcePathHelper = new PathHelper(Config.Instance.PathConfig.SourceDataPath);

        public override void Start(CancellationToken cancellationToken)
        {
            var dirsToCompress = _sourcePathHelper.DateDirectories.Where(t => IsOutOfKeptDays(t.Item2)).Select(t => t.Item1.FullName);

            var compressers = dirsToCompress.Select(sourceDir => new
            {
                TargetDir = sourceDir.Replace(Config.Instance.PathConfig.SourceDataPath, Config.Instance.PathConfig.CompressFolder),
                Compresser = new Compresser(sourceDir, Config.Instance.PathConfig.CompressedFileExtension)
            }).ToArray();

            var totalFileCount = compressers.Sum(c => c.Compresser.FileCount);
            var compressedFileCount = 0;

            Action<int> reportProgress = compressed => OnProgressChanged((int)((compressed) * 100.0 / totalFileCount));

            foreach(var compresser in compressers)
            {
                cancellationToken.ThrowIfCancellationRequested();

                // 在开始前报告进度
                reportProgress(compressedFileCount);

                if(Directory.Exists(compresser.TargetDir))
                {
                    Directory.Delete(compresser.TargetDir, true);
                }

                compresser.Compresser.FileCompressed += (sender, e) =>
                    reportProgress(compressedFileCount + e.Data);
                Directory.CreateDirectory(compresser.TargetDir);

                try
                {
                    compresser.Compresser.Compress(compresser.TargetDir, cancellationToken);
                }
                catch (OperationCanceledException)
                {
                    Directory.Delete(compresser.TargetDir, true);
                    throw;
                }

                compressedFileCount += compresser.Compresser.FileCount;

                // 删除原始解析后数据
                FileHelper.Retry(() => Directory.Delete(compresser.Compresser.SourceDir, true));
            }
        }

        private static bool IsOutOfKeptDays(DateTime date)
        {
            return date < DateTime.Today.AddDays(-Config.Instance.TaskConfig.RawDataKeptDays);
        }
    }
}
